using System;
using System.Collections.Generic;
using CLELCore.Assembly;
using CLELCore.Assembly.CLELInstructions;
using CLELCore.Assembly.Descriptors;
using CLELCore.Assembly.Descriptors.ClassDescriptors;
using CLELCore.Assembly.BlobStreams.BlobInfo;
using CLELCore.Assembly.Parser.ValidAssemblyParser;
using CLELCore.Assembly.Generator.ValidAssemblyGenerator;
using CLELCore.Assembly.Printer.AssemblyConsolePrinter;
using CLELCore.Assembly.MethodHeaderDataSections.MethodHeaderDataSectionRows;

namespace CLELCore
{
	public class CLEL : IDisposable
	{
		private String _path;
		private CLELAssembly _assembly;
		private CLELLogger _log;

		public String Path
		{
			get
			{
				return _path;
			}
		}

		public CLEL(String local_path)
		{
			LoadCLEL(new CLELFileReader(local_path));
		}

		public CLEL(ICLELReader reader)
		{
			LoadCLEL(reader);
		}

		private void LoadCLEL(ICLELReader reader)
		{
			if(reader == null)
				throw new ArgumentException("Reader cannot be null");
			_path = reader.Path;
			_log = new CLELLogger();
			CLELValidAssemblyParser parser = new CLELValidAssemblyParser(reader,_log);
			_assembly = new CLELAssembly(parser);
			reader.Dispose();
		}

		public void WriteAssembly(ICLELWriter writer)
		{
			if(writer == null)
				throw new ArgumentException("Writer cannot be null");
			CLELValidAssemblyGenerator generator = new CLELValidAssemblyGenerator(writer,_log);
			_assembly.Write(generator);
			writer.Dispose();
		}

		public void PrintAssembly(ICLELPrinter printer)
		{
			if(printer == null)
				throw new ArgumentException("Printer cannot be null");
			printer.Print(_assembly);
		}

		public void PrintCodeToConsole()
		{
			AssemblyConsolePrinter printer = new AssemblyConsolePrinter(AssemblyConsolePrinter.CODE_ONLY);
			PrintAssembly(printer);
		}

		//Assembly
		public int GetCodeSize()
		{
			return _assembly.GetCodeSize();
		}

		public int GetInstructionCount()
		{
			return _assembly.GetInstructionCount();
		}

		//Class
		public List<ClassDescriptor> GetInternalClasses()
		{
			return _assembly.GetInternalClasses();
		}
		
		public List<ClassDescriptor> GetExternalClasses()
		{
			return _assembly.GetExternalClasses();
		}

		public Token GetEntryPointToken()
		{
			return _assembly.GetEntryPointToken();
		}

		//Method
		public List<MethodDescriptor> GetMethodDescriptorsForClass(Token token)
		{
			return _assembly.GetMethodDescriptorsForClass(token);
		}

		public String GetMethodsName(Token token)
		{
			return _assembly.GetMethodsName(token);
		}
		
		public List<CLELInstruction> GetCodeForMethod(Token token)
		{
			return _assembly.GetCodeForMethod(token);
		}

		public MethodDescriptor GetMethodDescriptor(Token token)
		{
			return _assembly.GetMethodDescriptor(token);
		}
		
		public void SetMethodsCode(MethodDescriptor md,List<CLELInstruction> code,MethodLocalsBlobInfo locals)
		{
			_assembly.SetMethodsCode(md,code,locals);
		}

		public MethodLocalsBlobInfo GetMethodsLocals(Token token)
		{
			return _assembly.GetMethodsLocals(token);
		}

		public void Dispose()
		{
			_log.Dispose();
		}
	}
}
